/**
 * 币种因为不像国家接口那样很多，后端会一次返回所有的币种，
 * 因为本 service 会在初始化的时候，去获取所有的币种，并提供三个接口
 * 1. 原始的币种数据
 * 2. value 是币种对象的 options，供 select 使用
 * 3. label 是币种 name， value是币种 code 的 options, 供 select 使用
 */
import { HttpClient } from '@angular/common/http'
import { Observable, throwError, of } from 'rxjs'
import { catchError, map, mergeMap, switchMap } from 'rxjs/operators'
import { Injectable } from '@angular/core'

import { COMB_URL } from 'app/utils/contraints'
import { ObservableStore } from '@shared/classes/ObservableStoreClass'
import { transCurrenciesToValueOptions, transCurrenciesToCurrencyOptions } from 'app/utils/helpers'
import { ICurrencyOption, Currency } from '@shared/interfaces/common'
import { ISearchOption } from '@shared/interfaces/search'

@Injectable({
  providedIn: 'root',
})
export class CurrencyService {
  public allCurrencies$: ObservableStore<Currency[]> = new ObservableStore([])

  constructor(private http: HttpClient) {
    this.getAllCurrency().subscribe(currency => {
      this.allCurrencies$.setValue(currency)
    })
  }

  get currencies(): Currency[] {
    return this.allCurrencies$.value
  }

  get currencyStrOptions(): Observable<ISearchOption[]> {
    return this.allCurrencies$.value$.pipe(
      mergeMap(currencies => {
        if (currencies.length > 0) {
          return of(this.renderCurrenciesStrValue(currencies))
        }

        return this.getAllCurrency().pipe(
          mergeMap(c => {
            return of(this.renderCurrenciesStrValue(c))
          }),
        )
      }),
    )
  }

  getCurrencyOptions(): Observable<ICurrencyOption[]> {
    return this.allCurrencies$.value$.pipe(
      map(list => {
        return this.renderCurrencies(list)
      }),
    )
  }

  getCurrencySearchOptions(): Observable<ISearchOption[]> {
    return this.allCurrencies$.value$.pipe(
      map(list => {
        return this.renderCurrenciesStrValue(list)
      }),
    )
  }

  /** 返回全量币种信息
   */
  getAllCurrency(): Observable<Currency[]> {
    return this.getList()
  }

  /** 返回全量币种信息
   * insCode 和 intStoreCode 都没有传的话，就查询系统全部币种
   * insCode 有值就查询机构币种
   * intStoreCode 有值就查询门店币种
   * 如果两个值都有，优先查询门店币种
   */
  getList(insCode?: string, intStoreCode?: string): Observable<Currency[]> {
    const params: string[] = []
    if (insCode) {
      params.push(`insCode=${insCode}`)
    }
    if (intStoreCode) {
      params.push(`intStoreCode=${intStoreCode}`)
    }
    let url = `${COMB_URL}/camel/currencies`
    if (params.length) {
      url += `?${params.join('&')}`
    }

    return this.http.get<Currency[]>(url).pipe(
      map(res => {
        return res
      }),
      catchError(err => throwError(err)),
    )
  }

  getDecimalByCode(code: string): Observable<number> {
    return this.allCurrencies$.value$.pipe(
      switchMap(
        (currencies) => {
          const currency = currencies.find(c => c.code === code)
          if (currency) {
            return of(currency.decimal)
          }
          return of(0)
        }
      )
    )
  }

  private renderCurrencies(currencies: Currency[]): ICurrencyOption[] {
    return transCurrenciesToCurrencyOptions(currencies)
  }

  private renderCurrenciesStrValue(currencies: Currency[]): ISearchOption[] {
    return transCurrenciesToValueOptions(currencies)
  }
}
